package com.wf.atm.service;


import lombok.Data;
import com.wf.atm.dao.FileDao;
import com.wf.atm.dao.FileMapper;
import com.wf.atm.exception.ATMException;
import com.wf.atm.exception.BalanceNotEnoughException;
import com.wf.atm.exception.LoginException;
import com.wf.atm.exception.RegisterException;
import com.wf.atm.pojo.*;
import com.wf.atm.pojo.vo.RankVo;
import com.wf.atm.utils.MD5Utils;

import java.io.IOException;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;

/**
 * 银行类
 *
 * @author mpk
 * @since 2024/6/3 18:24:45
 */

@Data
public class Bank implements Serializable {


    private static final long serialVersionUID = 2085587214563731759L;
    /**
     * 账户对象
     */
 //   private List<Account> accounts = new ArrayList<>();

    /**
     * 单例
     */

    private static Bank instance;

    /**
     * 单例
     */
    private Bank() {

        if(instance != null)
        {
            throw new RuntimeException("单例模式不允许创建多个对象");
        }
    }


    public static Bank getInstance() {

        if (instance == null) {
            instance = new Bank();
        }
        return instance;
    }

    FileMapper mapper = new FileDao();


    /**
     * 账户注册
     */
    public Account register(String name, String password, String rePassword, String personId, String address,String email, int type)  throws RegisterException {

        if (password == null || rePassword == null || name == null || personId == null || email == null|| address == null) {
            throw new RegisterException("请填写完整信息！");

        }

        if (!password.equals(rePassword)) {
            throw new RegisterException("两次密码输入不一致，请重新输入");
        }
        /*   项目需求规定账户类型：0 – 储蓄账户  1 – 信用账户 2 – 可贷款储蓄账户 3– 可贷款信用账户*/


        password = MD5Utils.MD5(password);

        //862150212013020001(国家+邮编+年+月+序号)。
        StringBuilder stringBuilder = new StringBuilder();
        LocalDateTime now = LocalDateTime.now();
        int year = now.getYear();
        int month = now.getMonth().getValue();

        stringBuilder.append("86215021").append(year).append(String.format("%02d", month)).append(String.format("%04d", mapper.selectAll().size() + 1));
        String string = stringBuilder.toString();

        mapper.setId(string);

        Long id = mapper.getId();
        Account acc;
        if (type == 0) {
            acc = new SavingAccount(id, password, name, personId, address,email);
        } else if (type == 2) {
            acc = new LoanSavingAccount(id, password, name, personId,address, email);
        } else if (type == 1) {
            CreditAccount creditAccount = new CreditAccount(id, password, name, personId, address, email);
            creditAccount.setCeiling(5000.0);
            acc = creditAccount;

        } else if (type == 3) {

            LoanCreditAccount creditAccount = new LoanCreditAccount(id, password, name, personId, address, email);
            creditAccount.setCeiling(5000.0);
            acc = creditAccount;

        } else {
            throw new RegisterException("账户类型错误！");
        }


        mapper.insertAccount(acc);

       // accounts.add(acc);
        System.out.println("注册成功！");

        return acc;


    }


    /**
     * 用户登录
     *
     * @return 账户
     */
    public Account login(Long id, String password) throws  LoginException {

        if (id == null || password == null) {
            throw new LoginException("请填写完整信息！");
        }


        Account act = mapper.selectActByIdAndPwd(id, password);

        if (act != null) {
            System.out.println("登陆成功");
            return act;
        }


        throw new LoginException("用户名或密码错误");

    }

    /**
     * 存款
     *
     * @param money 存款金额
     */
    public Account deposit(Long id, double money) throws ATMException, LoginException {

        Account act = mapper.selectActById(id);

        if (act == null) {
            throw new LoginException("账户不存在！");
        }
        act.deposit(money);

        mapper.updateAccount(act);

        System.out.println("存款成功！！");
        return act;


    }

    /**
     * @param money 取款金额
     */
    public Account withdraw(Long id, String password, double money) throws LoginException, BalanceNotEnoughException {


        System.out.println("取款");

        Account act =login(id, password);

        act = act.withdraw(money);

        mapper.updateAccount(act);

        System.out.println("取款成功！！");

        return act;

    }


    /**
     * @param ceiling 透支额度
     */
    public Account updateCeiling(Long id, String password, double ceiling) throws ATMException, LoginException  {


        Account act = login(id, password);

        if (act instanceof CreditAccount) {
            ((CreditAccount) act).setCeiling(ceiling);
            mapper.updateAccount(act);
            return act;
        } else {
            throw new ATMException("账户类型错误！");
        }


    }


    /**
     * @param money 转账金额
     */
    public boolean transfer(Long from, String passwordFrom, Long to, double money) throws ATMException, LoginException, BalanceNotEnoughException  {


        Account account = login(from, passwordFrom);

        account.withdraw(money);

        Account deposit = deposit(to, money);

        mapper.updateAccount(account);

        mapper.updateAccount(deposit);

        return true;


    }


    /**
     * @return 银行所有账户余额总数
     */

    public double sumAllBalance()  {

        List<Account> list = mapper.selectAll();

        double sum = 0;
        for (Account account : list) {

            sum = sum + account.getBalance();
        }
        return sum;
    }

    /**
     * @return 所有信用账户透支额度总数
     */
    public double sumAllCeiling()  {

        double sum = 0;
        List<Account> list = mapper.selectAll();
        for (Account act : list) {

            if (act instanceof CreditAccount) {
                CreditAccount account = (CreditAccount) act;
                sum = sum + account.getCeiling();
            }

        }
        return sum;
    }


    /**
     * 贷款
     */

    public Account requestLoan(Long id, double money) throws ATMException, BalanceNotEnoughException, LoginException {


        Account act = mapper.selectActById(id);

        if (act != null) {

            if (act instanceof LoanSavingAccount) {

                LoanSavingAccount lsa = (LoanSavingAccount) act;

                lsa.requestLoan(money);

                mapper.updateAccount(lsa);
                return act;

            } else if (act instanceof LoanCreditAccount) {

                LoanCreditAccount lca = (LoanCreditAccount) act;

                lca.requestLoan(money);
                mapper.updateAccount(lca);
                return act;

            } else {
                throw new ATMException("该账户为非贷款用户！");
            }

        }

        throw new LoginException("用户不存在！");


    }


    /**
     * 还贷款
     */
    public Account payLoan(Long id, double money) throws ATMException, LoginException {


        Account act = mapper.selectActById(id);
        if (act != null) {

            if (act instanceof LoanSavingAccount) {

                LoanSavingAccount lsa = (LoanSavingAccount) act;
                lsa.payLoan(money);
                mapper.updateAccount(lsa);
                return lsa;
            } else if (act instanceof LoanCreditAccount) {

                LoanCreditAccount lca = (LoanCreditAccount) act;
                lca.payLoan(money);
                return lca;
            } else {
                throw new ATMException("该账户为分贷款用户！");
            }
        }

        throw new LoginException("用户不存在！");
    }


    /**
     * 贷款总额
     */
    public double sumAllLoan()  {

        double sum = 0;
        List<Account> list = mapper.selectAll();
        for (Account account : list) {


            if (account instanceof  LoanSavingAccount) {

                LoanSavingAccount loanSavingAccount = (LoanSavingAccount) account;
                sum += loanSavingAccount.getLoanAmount();
            } else if (account instanceof  LoanCreditAccount) {

                LoanCreditAccount loanCreditAccount = (LoanCreditAccount) account;
                sum += loanCreditAccount.getLoanAmount();

            }
        }
        return sum;

    }

    /**
     * 资产排名
     */
    public Set<RankVo> assetRanking() {

        List<Account> list = mapper.selectAll();
        Map<String, Double> balances = list
                .stream()
                .collect(Collectors.groupingBy(
                        account -> account.getName() + "-" + account.getPersonId(),
                        Collectors.summingDouble(Account::getBalance)
                ));
// 打印排序后的结果
        TreeSet<RankVo> vos = new TreeSet<>(Comparator.comparingDouble(RankVo::getBalance).thenComparing(RankVo::getName).reversed());
        String name;
        String personId;
        for (Map.Entry<String, Double> entry : balances.entrySet()) {
            String[] strings = entry.getKey().split("-");
            name = strings[0];
            personId = strings[1];
            RankVo rankVo = new RankVo(name, personId, balances.get(entry.getKey()));
            vos.add(rankVo);
        }

        return vos;

    }


}
